using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace WindowsGame.CollectibleComponents
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class CollectibleComponent : Microsoft.Xna.Framework.GameComponent
    {
        //Sprites
        Texture2D tBattery1;
        Texture2D tPaperBag1;

        //Boxes for collision for hit collision, drawing and animating
        Rectangle hitBox;
        Rectangle srcBox; //Use this to animate sprite. Remove if not in use
        Vector2 hitBoxSize;
        Vector2 initialPosition;
        Vector2 location;

        float rotation = 0;
        bool rotate = true;

        const float gravity = 0.1f;
        float xVel, yVel;
        float speedMultiplier;

        Random rnd;

        //Get map component to be able to get map bounds
        MapComponent map;
        List<MapComponent.Bounds> boundList;

        //Enum for different types of collectible. Will be used to determine movement behaviour, graphics etc. 
        //Make public to let other components access this, read only
        public enum CollectibleType
        {
            Battery,
            PaperBag
        }
        CollectibleType currentType;

        enum MovementState
        {
            Stationary,
            OnGround,
            Falling,
            Jumping
        }
        MovementState movementState;

        //Constructor
        public CollectibleComponent(Game game, Vector2 size, Vector2 spawnPosition, CollectibleType type, MapComponent map, float speedMultiplier, Texture2D paperBag, Texture2D battery, List<MapComponent.Bounds> boundList)
            : base(game)
        {
            tBattery1 = battery;
            tPaperBag1 = paperBag;

            this.boundList = boundList;

            //Allow for different sizes on enemy. Determined by spawner
            hitBoxSize = size;
            initialPosition = spawnPosition;
            currentType = type;
            this.speedMultiplier = speedMultiplier;

            //Get map component
            this.map = map;
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            //Round to 0 decimals and cast to int, to prevent problems
            location = new Vector2(initialPosition.X, initialPosition.Y);
            hitBox = new Rectangle((int)Math.Round(initialPosition.X, 0), (int)Math.Round(initialPosition.Y, 0), (int)Math.Round(hitBoxSize.X, 0), (int)Math.Round(hitBoxSize.Y, 0));
            srcBox = new Rectangle(0, 0, 32, 32);
            movementState = MovementState.Falling;

            rnd = new Random();

            base.Initialize();
        }

        

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            //Calculate gravity
            if (yVel < 10)
                yVel += gravity;

            switch (currentType)
            {
                case CollectibleType.Battery:
                    //This object will be stationary. For now it does not need any logic
                    movementState = MovementState.Stationary;
                    xVel = 0;
                    yVel = 0;

                    break;
                case CollectibleType.PaperBag:
                    xVel = -1 * speedMultiplier;

                    if (movementState == MovementState.Stationary)
                        rotate = false;
                    else
                        rotate = true;

                    for (int i = 0; i < boundList.Count; i++)
                    {
                        //Check collision with objects in bound list
                        if (hitBox.Intersects(boundList[i].rect))
                        {
                            //Check wheter bound is ground or not
                            if (boundList[i].type == MapComponent.BoundType.Solid || boundList[i].type == MapComponent.BoundType.Passable)
                            {
                                //Check if hitbox is below box it collided with
                                if (hitBox.Bottom >= boundList[i].rect.Top && hitBox.Bottom <= boundList[i].rect.Top + 5 && yVel < 0)
                                    location.Y = boundList[i].rect.Top - hitBox.Height + 1; //Put on top of bound box

                                //If collision and y velocity i more than 0, set it to 0
                                if (hitBox.Bottom > boundList[i].rect.Top && hitBox.Bottom < boundList[i].rect.Top + 7 && yVel > 0)
                                {
                                    yVel = 0;
                                    movementState = MovementState.OnGround;
                                }

                                //If hitting solid object on the side
                                if (boundList[i].type == MapComponent.BoundType.Solid)
                                {
                                    //Stop x velocity if hitbox bottom is below bounding box's top
                                    //Also check if falling or "jumping"
                                    if (hitBox.Bottom > boundList[i].rect.Top + 7)
                                    {
                                        xVel = 0;
                                        //Put to left of bound box
                                        location.X = boundList[i].rect.Right - 1;
                                        movementState = MovementState.Stationary;
                                    }
                                }


                                //Make bag blow upwards
                                if (rnd.Next(0, 500) == 1)
                                    yVel = rnd.Next(-7, -3); //Make bigger jump sometimes
                                else if (rnd.Next(0,50) == 1)
                                    yVel = rnd.Next(-2, -1); //Make small jumps

                            }
                            else
                                movementState = MovementState.Falling;
                        }
                        //If y velocity is negative, the collectible is most probably "jumping"
                        if (yVel < 0)
                            movementState = MovementState.Jumping;
                    }

                    break;
                default:
                    break;
            }

            if (rotate)
                rotation -= 0.005f * speedMultiplier * gameTime.ElapsedGameTime.Milliseconds;

            //Move collectible
            location.X += xVel;
            location.Y += yVel;

            hitBox.X = (int)location.X;
            hitBox.Y = (int)location.Y;

            base.Update(gameTime);
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Camera2DComponent camera)
        {
            //Begin spritebatch with camera matrix
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, camera.getMatrix());

            if (currentType == CollectibleType.Battery)
            {
                spriteBatch.Draw(tBattery1, hitBox, Color.White);
            }
            else if (currentType == CollectibleType.PaperBag)
            {
                //Draw this using rotation, to rotate while moving. Set origin in middle of sprite
                //Create new rectangle. Rotation will offset sprite, which causes issues
                Rectangle tempHitBox = new Rectangle(hitBox.X + hitBox.Width / 2, hitBox.Y + hitBox.Height / 2, hitBox.Width, hitBox.Height);
                spriteBatch.Draw(tPaperBag1, tempHitBox, srcBox, Color.White, rotation, new Vector2(srcBox.Width / 2, srcBox.Height / 2), SpriteEffects.None, 1);           
            }


            spriteBatch.End();
        }

        public Vector2 GetPosition() { return this.location; }

        public Rectangle GetHitbox() { return this.hitBox; }
    }
}
